#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define getjcb(type) (type*)malloc(sizeof(type))
#define NULL 0

int n = 0, time = 0;
float eti = 0, ewi = 0;

struct jcb {
	char name[10];           /* 作业名 */
	char state;              /* 作业状态 */
	int ts;                  /* 提交时间 */
	int tb;                  /* 开始运行时间 */
	int tc;                  /* 完成时间 */
	float ti;                /* 周转时间 */
	float wi;                /* 带权周转时间 */
	int ntime;               /* 作业所需运行时间 */
	int priority;            /* 优先级 */
	struct jcb* link;        /* 结构体指针 */
};

typedef struct jcb JCB;

JCB* head = NULL; // 全局声明 head

void initial();
void print(JCB* pr);
void last();
void fcfs();
void sjf();
void priority_scheduling();
void run_job(JCB* p);

int main() {
	initial();
	int m;
	char str[100] = "\nselect algorithm\n1.FCFS\n2.SJF\n3.Priority Scheduling\n";
	printf("%s", str);
	m = getchar() - 48;

	if (1 <= m && m <= 3) {
		switch (m) {
		case 1:
			fcfs();
			break;
		case 2:
			sjf();
			break;
		case 3:
			priority_scheduling();
			break;
		}
	}
	else {
		printf("\nselect error!try again...\n");
		main();
	}
	last();
	printf("\nfinished!");
	getchar();
	return 0;
}

void initial() {
	int i;
	printf("\nInput jcb num\n");
	scanf("%d", &n);
	printf("Input\nname\tts\tntime\tpriority\n");
	JCB* q = NULL;
	for (i = 0; i < n; i++) {
		JCB* p = getjcb(JCB);
		scanf("%s\t%d\t%d\t%d", &p->name, &p->ts, &p->ntime, &p->priority);
		p->state = 'W';
		p->link = NULL;
		if (head == NULL) {
			head = q = p;
		}
		else {
			q->link = p;
			q = p;
		}
	}
}

void print(JCB* pr) {
	JCB* p;
	printf("\ntime=%d", time);

	printf("\nname\tstate\tts\tntime\tpriority\ttb\ttc\tti\twi\n");
	printf("%s\t%c\t%d\t%d\t%d\t%d\t%d\t%4.2f\t%4.2f\n",
		pr->name, pr->state, pr->ts, pr->ntime, pr->priority, pr->tb, pr->tc, pr->ti, pr->wi);

	p = head;
	do {
		if (p->state == 'W')
			printf("%s\t%c\t%d\t%d\t%d\n",
				p->name, p->state, p->ts, p->ntime, p->priority);

		p = p->link;
	} while (p != NULL);
	p = head;
	do {
		if (p->state == 'F')
			printf("%s\t%c\t%d\t%d\t%d\t%d\t%d\t%4.2f\t%4.2f\n",
				p->name, p->state, p->ts, p->ntime, p->priority, p->tb, p->tc, p->ti, p->wi);
		p = p->link;
	} while (p != NULL);
}

void last() {
	eti /= n;
	ewi /= n;
	printf("\neti=%7.3f\tewi=%7.3f\n", eti, ewi);
}

void fcfs() {
	JCB* min = NULL;
	int i, iden;
	for (i = 0; i < n; i++) {
		JCB* p = head;
		iden = 1;
		do {
			if (p->state == 'W' && p->ts <= time) {
				if (iden) {
					min = p;
					iden = 0;
				}
				else if (p->ts < min->ts) min = p;
			}
			p = p->link;
		} while (p != NULL);

		if (iden) {
			i--;
			printf("\ntime=%d:\tno JCB submib...wait...", time);
			time++;
			if (time > 100) {
				printf("\nruntime is too long...error");
				getchar();
			}
		}
		else {
			run_job(min);
		}
	}
}

void sjf() {
	JCB* min = NULL;
	int i, iden;
	for (i = 0; i < n; i++) {
		JCB* p = head;
		iden = 1;
		do {
			if (p->state == 'W' && p->ts <= time) {
				if (iden) {
					min = p;
					iden = 0;
				}
				else if (p->ntime < min->ntime) min = p;
			}
			p = p->link;
		} while (p != NULL);

		if (iden) {
			i--;
			printf("\ntime=%d:\tno JCB submib...wait...", time);
			time++;
			if (time > 100) {
				printf("\nruntime is too long...error");
				getchar();
			}
		}
		else {
			run_job(min);
		}
	}
}

void priority_scheduling() {
	JCB* max = NULL;
	int i, iden;
	for (i = 0; i < n; i++) {
		JCB* p = head;
		iden = 1;
		do {
			if (p->state == 'W' && p->ts <= time) {
				if (iden) {
					max = p;
					iden = 0;
				}
				else if (p->priority > max->priority) max = p;
			}
			p = p->link;
		} while (p != NULL);

		if (iden) {
			i--;
			printf("\ntime=%d:\tno JCB submib...wait...", time);
			time++;
			if (time > 100) {
				printf("\nruntime is too long...error");
				getchar();
			}
		}
		else {
			run_job(max);
		}
	}
}

void run_job(JCB* p) {
	p->tb = time;
	p->state = 'R';
	p->tc = p->tb + p->ntime;
	p->ti = (float)(p->tc - p->ts);
	p->wi = (float)(p->ti / p->ntime);
	eti += p->ti;
	ewi += p->wi;
	print(p);
	time += p->ntime;
	p->state = 'F';
	printf("\n%s has been finished!\npress any key to continue...\n", p->name);
	getchar();
}

